package com.example.study.commen.aop;

import com.example.study.commen.cdc.DataChangeInfo;
import com.example.study.commen.websocket.bean.WebSocketVO;
import com.example.study.config.redis.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.flink.streaming.api.functions.sink.SinkFunction;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;


/*
 * 1.@Pointcut：定义一个切面，即上面所描述的关注的某件事入口。
 * 2.@Before：在做某件事之前做的事。
 * 3.@After：在做某件事之后做的事。
 * 4.@AfterReturning：在做某件事之后，对其返回值做增强处理。
 * 5.@AfterThrowing：在做某件事抛出异常时，处理。
 */
@Aspect
@Component
@Slf4j
public class LogAspectHandler {

    @Resource
    RedisUtil redisUtil;

    /**
     * @Pointcut 注解：用来定义一个切面（切入点），即上文中所关注的某件事情的入口。
     * 切入点决定了连接点关注的内容，使得我们可以控制通知什么时候执行。
     * <p>
     * 定义一个切面，拦截com.zhengzhou.springboot_6_6.controller包和子包下的所有方法
     * Object msg, Message message, Channel channel
     */
    @Pointcut(value = "execution(* com.example.study.controller.ShiroController.getUserList(..))&&args(name)", argNames = "name")
    public void pointCut(String name) {

    }


    @Before(value = "pointCut(name)", argNames = "joinPoint,name")
    public void beforeAdvice(JoinPoint joinPoint, String name) {
        log.info("====doBefore方法进入了====");

        // 获取签名
        Signature signature = joinPoint.getSignature();
        // 获取切入的包名
        String declaringTypeName = signature.getDeclaringTypeName();
        // 获取即将执行的方法名
        String funcName = signature.getName();
        log.info("即将执行方法为: {}，属于{}包", funcName, declaringTypeName);

        // 也可以用来记录一些信息，比如获取请求的url和ip
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 获取请求url
        String url = request.getRequestURL().toString();
        // 获取请求ip
        String ip = request.getRemoteAddr();
        log.info("用户请求的url为：{}，ip地址为：{}", url, ip);
    }

    @After(value = "pointCut(name)", argNames = "joinPoint,name")
    public void afterAdvice(JoinPoint joinPoint, String name) {
        log.info("====doAfter方法进入了====");
        Signature signature = joinPoint.getSignature();
        String method = signature.getName();
        log.info("方法{}已经执行完  " + Arrays.toString(joinPoint.getArgs()), method);
    }

    /**
     * 在上面定义的切面方法返回后执行该方法，可以捕获返回对象或者对返回对象进行增强
     *
     * @param joinPoint joinPoint
     * @param result    result
     */
    @AfterReturning(pointcut = "pointCut(name)", returning = "result", argNames = "joinPoint,result,name")
    public void doAfterReturning(JoinPoint joinPoint, Object result, String name) {

        Signature signature = joinPoint.getSignature();
        String classMethod = signature.getName();
        log.info("方法{}执行完毕，返回参数为：{}", classMethod, result);
        // 实际项目中可以根据业务做具体的返回值增强
        log.info("对返回参数进行业务上的增强：{}", result + "增强版");
    }

//==================

    @Pointcut(value = "execution(* com.example.study.commen.cdc.DataChangeSink.invoke(..))&&args(value,context)", argNames = "value,context")
    public void pointCut_CDC(DataChangeInfo value, SinkFunction.Context context) {

    }

//    @AfterReturning(pointcut = "pointCut_CDC(value,context)", returning = "result", argNames = "joinPoint,result,value,context")
//    public void doAfterReturning_cdc(JoinPoint joinPoint, Object result, DataChangeInfo value, SinkFunction.Context context) {
//
//        Signature signature = joinPoint.getSignature();
//        String classMethod = signature.getName();
//        log.info("方法{}执行完毕，返回参数为：{}", classMethod, result);
//        // 实际项目中可以根据业务做具体的返回值增强
//        log.info("对返回参数进行业务上的增强：{}", result + "增强版");
//    }


    @After(value = "pointCut_CDC(value,context)", argNames = "joinPoint,value,context")
    public void afterAdvice_CDC(JoinPoint joinPoint, DataChangeInfo value, SinkFunction.Context context) {
        log.info("====doAfter方法进入了====");
//        Signature signature = joinPoint.getSignature();
//        String method = signature.getName();
//        log.info("方法{}已经执行完  " + Arrays.toString(joinPoint.getArgs()), method);
//        log.info(value.getAfterData());
        redisUtil.set("DataChangeInfo", value.getAfterData(), 60 * 10);
    }
    //chat

//    @Pointcut(value = "execution(* com.example.study.commen.websocket.WebSocketSever.sendMessageByUser(..))&&args(userId,message)", argNames = "userId,message")
//    public void pointChatCut(Integer userId, WebSocketVO message) {
//
//    }
//
//    @After(value = "pointChatCut(userId,message)", argNames = "joinPoint,userId,message")
//    public void afterAdvice_CHat(JoinPoint joinPoint, Integer userId, WebSocketVO message) {
//        log.info("====doAfter方法进入了===="+userId+"_"+message.getMessage());
//
//    }


    @Pointcut(value = "execution(* com.example.study.commen.websocket.WebUtils.getMsg(..))&&args(message)", argNames = "message")
    public void pointChatCut( WebSocketVO message) {

    }

    @After(value = "pointChatCut(message)", argNames = "joinPoint,message")
    public void afterAdvice_CHat(JoinPoint joinPoint, WebSocketVO message) {
        log.info("====doAfter方法进入了====_"+message.getMessage());

    }
}
